package datasource.image;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;

import javax.imageio.ImageIO;

import thesis.DataObject;
import thesis.Summary;
import experiment.Dimension;
import experiment.MainExp;

public class MIRFlickr {
	public static String root = "C:\\home\\work\\tweet_project\\datasets\\MIRFlickr";

	private static class UserGroup implements Comparable<UserGroup> {
		public String id;
		public int count;

		public UserGroup(String id, int count) {
			this.id = id;
			this.count = count;
		}

		@Override
		public int compareTo(UserGroup g) {
			// TODO Auto-generated method stub
			if (count > g.count)
				return -1;
			else if (count == g.count)
				return 0;
			else
				return 1;
		}
	}

	private static String parseExif(String name) {
		String time = null;
		try {
			BufferedReader br = new BufferedReader(new FileReader(name));
			String line = null;
			while ((line = br.readLine()) != null) {
				line = line.trim();
				String value = br.readLine().trim();
				if (line.equals("-Date and Time")) {
					time = value;
					break;
				}
			}
			br.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return time;
	}

	private static String parseLicense(String name) {
		String userId = null;
		try {
			BufferedReader br = new BufferedReader(new FileReader(name));
			String line = null;
			while ((line = br.readLine()) != null) {
				StringTokenizer st = new StringTokenizer(line, ":");
				String att = st.nextToken().trim();
				if (att.equals("Owner id")) {
					userId = st.nextToken().trim();
					break;
				}
			}
			br.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return userId;
	}

	private static Set<String> parseTags(String name) {
		Set<String> tags = new HashSet<String>();
		try {
			BufferedReader br = new BufferedReader(new FileReader(name));
			String line = null;
			while ((line = br.readLine()) != null) {
				tags.add(line.trim());
			}
			br.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return tags;
	}

	public static ImageObj[] readData(String root) throws IOException {
		String exifDir = root + "/meta/exif/";
		String licenseDir = root + "/meta/license/";
		String tagDir = root + "/meta/tags_raw/";
		// String imageDir = root + "/images/";
		final int dataSize = 25000;
		ImageObj[] images = new ImageObj[dataSize];
		for (int i = 0; i < images.length; i++) {
			int iid = i + 1;
			if (i % 1000 == 0) {
				System.out.println("Parsing: " + iid + "-" + (iid + 998));
			}
			String userId = parseLicense(licenseDir + "license" + iid + ".txt");
			Set<String> tags = parseTags(tagDir + "tags" + iid + ".txt");
			String date = parseExif(exifDir + "exif" + iid + ".txt");
			images[i] = new ImageObj(userId, iid, tags, date);
		}
		return images;
	}

	public static HashMap<String, ArrayList<ImageObj>> aggregateImagesByUserId(
			ImageObj[] objs) {
		HashMap<String, ArrayList<ImageObj>> map = new HashMap<String, ArrayList<ImageObj>>();
		for (ImageObj obj : objs) {
			ArrayList<ImageObj> images = map.get(obj.userId);
			if (images == null) {
				images = new ArrayList<ImageObj>();
				map.put(obj.userId, images);
			}
			images.add(obj);
		}
		return map;
	}

	private static void processEvent(ArrayList<ImageObj> images) {
		EventClassifier classifier = new EventClassifier("res/events.txt");
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		for (ImageObj img : images) {
			classifier.classifyImage(img);
		}
	}

	private static void processVisual(ArrayList<ImageObj> images) {
		String anotationDir = root + "/annotations-general/";
		HashMap<Long, ImageObj> id2img = new HashMap<Long, ImageObj>();
		HashMap<String, HashSet<Long>> concept2img = new HashMap<String, HashSet<Long>>();
		for (ImageObj obj : images) {
			id2img.put(obj.getDbId(), obj);
		}
		File dir = new File(anotationDir);
		for (File file : dir.listFiles()) {
			String fileName = file.getName();
			if (fileName.endsWith(".txt")) {
				try {
					String concept = fileName.substring(0,
							fileName.indexOf('.'));
					BufferedReader br = new BufferedReader(new FileReader(file));
					String line;
					HashSet<Long> ids = new HashSet<Long>();
					while ((line = br.readLine()) != null) {
						long id = Long.parseLong(line);
						ids.add(id);
					}
					for (Long id : ids) {
						ImageObj tmpObj = id2img.get(id);
						if (tmpObj != null) {
							tmpObj.addConcept(concept, 1.0);
						}

					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		}
	}

	private static ArrayList<ImageObj> processUserId(ImageObj[] images,
			int numUserToReturn, int numObjToReturn) {
		HashMap<String, ArrayList<ImageObj>> map = aggregateImagesByUserId(images);
		ArrayList<UserGroup> list = new ArrayList<UserGroup>();
		for (String key : map.keySet()) {
			ArrayList<ImageObj> objs = map.get(key);
			list.add(new UserGroup(key, objs.size()));
		}
		Collections.sort(list);
		ArrayList<ImageObj> imagesToReturn = new ArrayList<ImageObj>();
		for (int i = 0; i < numUserToReturn && i < list.size(); i += 1) {
			for (ImageObj obj : map.get(list.get(i).id)) {
				if (imagesToReturn.size() == numObjToReturn) {
					return imagesToReturn;
				}
				imagesToReturn.add(obj);
			}
		}
		return imagesToReturn;
	}

	public static void writeImage(Summary summary, String dir) {
		String imageDir = root + "/images/";
		String outputDir = root + "/outputs/" + dir + "/";
		File file = new File(outputDir);
		if (file.exists()) {
			file.delete();
		}
		file.mkdir();
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputDir
					+ "dimension.txt"));
			for (DataObject obj : summary.getMemoryTweets()) {
				ImageObj img = (ImageObj) obj;
				BufferedImage image = null;

				image = ImageIO.read(new File(imageDir + "im" + img.getDbId()
						+ ".jpg"));
				ImageIO.write(image, "jpg",
						new File(outputDir + "im" + img.getDbId() + ".jpg"));
				bw.write(img.toString());
			}
			bw.flush();
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private static List<Dimension> generateDim(ArrayList<ImageObj> objs) {
		Dimension timeDim = new Dimension();
		Dimension eventDim = new Dimension();
		Dimension idDim = new Dimension();
		Dimension visualDim = new Dimension();
		for (ImageObj obj : objs) {
			// time ------------
			if (obj.time != null) {
				HashMap<Long, Double> timeValue = timeDim.value2obj.get(""
						+ obj.timeClusterID);
				if (timeValue == null) {
					timeValue = new HashMap<Long, Double>();
					timeDim.value2obj.put("" + obj.timeClusterID, timeValue);
				}
				timeValue.put(obj.getDbId(), 1.0);
			}
			// event -----------
			for (String eventTag : obj.getEventTags().keySet()) {
				double prob = obj.getEventTags().get(eventTag);
				HashMap<Long, Double> eventValue = eventDim.value2obj
						.get(eventTag);
				if (eventValue == null) {
					eventValue = new HashMap<Long, Double>();
					eventDim.value2obj.put(eventTag, eventValue);
				}
				eventValue.put(obj.getDbId(), prob);
			}
			// userId -----------
			HashMap<Long, Double> idValue = idDim.value2obj.get(obj.userId);
			if (idValue == null) {
				idValue = new HashMap<Long, Double>();
				idDim.value2obj.put(obj.userId, idValue);
			}
			idValue.put(obj.getDbId(), 1.0);
			// visual concepts -----------
			for (String concept : obj.getConcepts().keySet()) {
				double prob = obj.getConcepts().get(concept);
				HashMap<Long, Double> visualValue = visualDim.value2obj
						.get(concept);
				if (visualValue == null) {
					visualValue = new HashMap<Long, Double>();
					visualDim.value2obj.put(concept, visualValue);
				}
				visualValue.put(obj.getDbId(), prob);
			}
		}
		List<Dimension> dimensions = new ArrayList<Dimension>();
		dimensions.add(timeDim);
		dimensions.add(eventDim);
		dimensions.add(idDim);
		dimensions.add(visualDim);
//		eventDim.xor = false;
		visualDim.xor = false;
		return dimensions;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			ImageObj[] images = readData(root);
			BufferedWriter bw = new BufferedWriter(new FileWriter(root
					+ "/metaFile.txt"));
			for (ImageObj image : images) {
				bw.append(image.toString() + "\n");
			}
			bw.flush();
			bw.close();
			ArrayList<ImageObj> userFilteredImages = processUserId(images,
					100, 20000);

			processEvent(userFilteredImages);
			processVisual(userFilteredImages);
			TimeClustering.cluster(userFilteredImages,15,5);
			List<Dimension> dimensions = generateDim(userFilteredImages);
			HashMap<Long, DataObject> objects = new HashMap<Long, DataObject>();
			for (ImageObj obj : userFilteredImages) {
				obj.setQuality(new Random().nextDouble());
				objects.put(obj.getDbId(), obj);
			}
			ArrayList<Double> weights = new ArrayList<Double>();
			for (int i = 0; i < dimensions.size(); i++) {
				weights.add(1.0);
			}
			MainExp.runSummarizer(objects, dimensions, weights, 0.0, 0.0, 1);
			// Visualizer.visualize(objects, dimensions, weights, 0.0, 0.0, 1);
			// RobustExp.testRobust(objects, dimensions, weights, 0.0, 0.0, 1);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
